if(typeof Cc == "undefined")
	var Cc = Components.classes;
if(typeof CC == "undefined")
	var CC = Components.classes;
if(typeof CU == "undefined")
	var CU = Components.utils;
if(typeof Cu == "undefined")
	var Cu = Components.utils;
if(typeof CR == "undefined")
	var CR = Components.results;
if(typeof Cr == "undefined")
	var Cr = Components.results;
if(typeof Ci == "undefined")
	var Ci = Components.interfaces;
if(typeof CI == "undefined")
	var CI = Components.interfaces;
const IOS = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);
const OS = CC['@mozilla.org/observer-service;1'].getService(CI.nsIObserverService);
const LOADER = CC["@mozilla.org/moz/jssubscript-loader;1"].getService(CI.mozIJSSubScriptLoader);
const _INCLUDED = {};

const NS_OK = 0;
const NS_BINDING_ABORTED = 0x804b0002;
const NS_BINDING_REDIRECTED = 0x804b0003;
const NS_ERROR_UNKNOWN_HOST = 0x804b001e;
const NS_ERROR_REDIRECT_LOOP = 0x804b001f;
const NS_ERROR_CONNECTION_REFUSED = 0x804b000e;
const NS_ERROR_NOT_AVAILABLE = 0x804b0111;

const LOG_CONTENT_BLOCK = 1;
const LOG_CONTENT_CALL = 2;
const LOG_CONTENT_INTERCEPT = 4;
const LOG_CHROME_WIN = 8;
const LOG_XSS_FILTER = 16;
const LOG_INJECTION_CHECK = 32;
const LOG_DOM = 64;
const LOG_JS = 128;
const LOG_LEAKS = 1024;
const LOG_SNIFF = 2048;
const LOG_CLEARCLICK = 4096;
const LOG_ABE = 8192;

const HTML_NS = "http://www.w3.org/1999/xhtml";

const WHERE_UNTRUSTED = 1;
const WHERE_TRUSTED = 2;
const ANYWHERE = 3;

const INCLUDE = function(name) {
  if (arguments.length > 1)
    for (var j = 0, len = arguments.length; j < len; j++)
      INCLUDE(arguments[j]);
  else if (!_INCLUDED[name]) {
    try {
      LOADER.loadSubScript("chrome://xulschoolhello/content/" + name + ".js");
      _INCLUDED[name] = true;
    } catch(e) {
      dump("INCLUDE " + name + ": " + e + "\n");
    }
  }
}

var ABE = {
  consoleDump: false,
  log: function(str) {
    https_everywhereLog(WARN, str);
  }
};

function https_everywhereLog(level, str) {
	dump(str);
}

function xpcom_generateQI(iids) {
  var checks = [];
  for each (var iid in iids) {
    checks.push("CI." + iid.name + ".equals(iid)");
  }
  var src = checks.length
    ? "if (" + checks.join(" || ") + ") return this;\n"
    : "";
  return new Function("iid", src + "throw Components.results.NS_ERROR_NO_INTERFACE;");
}

INCLUDE('IOUtil','ChannelReplacement');

/**
 * XULSchoolChrome namespace.
 */
if ("undefined" == typeof(XULSchoolChrome)) {
  var XULSchoolChrome = {};
};

function GM_deepWrappersEnabled(someXPCObject) {
  // the old school javacript wrappers had this property containing their
  // untrusted variable. the new ones don't.
  return !(new XPCNativeWrapper(someXPCObject).mUntrustedObject);
}

function GM_isGreasemonkeyable(url) {
  var scheme = Components.classes["@mozilla.org/network/io-service;1"]
               .getService(Components.interfaces.nsIIOService)
               .extractScheme(url);

  return (scheme == "http" || scheme == "https" || scheme == "file" ||
          url.match(/^about:cache/)) && !/hiddenWindow\.html$/.test(url);
}

/**
 * Controls the browser overlay for the Hello World extension.
 */
XULSchoolChrome.BrowserOverlay = {
  /**
   * Says 'Hello' to the user.
   */
  sayHello : function(aEvent) {
    let stringBundle = document.getElementById("xulschoolhello-string-bundle");
    let message = stringBundle.getString("xulschoolhello.greeting.label");

    window.alert(message);
  },
  init: function() {
        // The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
        if(gBrowser) {
			dump('hello:gBrowser\n');
			gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
		}
  },
  onPageLoad: function(aEvent) {
        //var doc = aEvent.originalTarget; // doc is document that triggered the event
        //var win = doc.defaultView; // win is the window for the doc
        // test desired conditions and do something
        // if (doc.nodeName == "#document") return; // only documents
        // if (win != win.top) return; //only top window.
        // if (win.frameElement) return; // skip iframes/frames
        //alert("page is loaded \n" +doc.location.href);
		//if (doc.nodeName == "#document") {
		//	//alert(doc.body);
		//	var div = doc.createElement("div");
		//	div.innerHTML='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbb';
		//	doc.body.appendChild(div);
		//}
		
		var e = aEvent;

		if (GM_deepWrappersEnabled(window)) {
			dump('In GM_deepWrappersEnabled\n');
			// when deep wrappers are enabled, e.target is already a deep xpcnw
			unsafeWin = e.target.defaultView;

			// in DPa2, there was a bug that made this *not* a deep wrapper.
			if (unsafeWin.wrappedJSObject) {
			  unsafeWin = unsafeWin.wrappedJSObject;
			}

			href = e.target.location.href;
		} else {
			// otherwise we need to wrap it manually
			unsafeWin = new XPCNativeWrapper(
						  new XPCNativeWrapper(e, "target").target,
						  "defaultView").defaultView;
			href = new XPCNativeWrapper(
					  new XPCNativeWrapper(unsafeWin, "location").location,
					  "href").href;
		}

		if (GM_isGreasemonkeyable(href)) {
			gmSvc = Components.classes["@mozilla.org/mygrease;1"]
							 .getService(Components.interfaces.nsIMyGrease);
							 
			gmSvc.domContentLoaded({ wrappedJSObject: unsafeWin }, '');
		}
  }
};
//window.addEventListener("load", function load(event){
//	dump('hello:addEvent\n');
//    window.removeEventListener("load", load, false); //remove listener, no longer needed
//    XULSchoolChrome.BrowserOverlay.init();  
//},false);

try {
	//largely from firebug. should refactor 
	if (typeof Cc == "undefined") {
		var Cc = Components.classes;
		var Ci = Components.interfaces;
	}
	if (typeof CCIN == "undefined") {
		function CCIN(cName, ifaceName){
			return Cc[cName].createInstance(Ci[ifaceName]);
		}
	}
	if (typeof CCSV == "undefined") {
		function CCSV(cName, ifaceName){
			if (Cc[cName]) 
				return Cc[cName].getService(Ci[ifaceName]); // if fbs fails to load, the error can be _CC[cName] has no properties
			else 
				dump("CCSV fails for cName:" + cName); 
		};
	}
	 
	function TracingListener() {
		//this.receivedData = [];
	}
		
	TracingListener.prototype = {
	    originalListener: null,
	    receivedData: null,   // array for incoming data.
	
	    onDataAvailable: function(request, context, inputStream, offset, count) {
	        var binaryInputStream = CCIN("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
	        var storageStream = CCIN("@mozilla.org/storagestream;1", "nsIStorageStream");
	        binaryInputStream.setInputStream(inputStream);
	        storageStream.init(8192, count, null);
	        
			var binaryOutputStream = CCIN("@mozilla.org/binaryoutputstream;1",
	                "nsIBinaryOutputStream");
	           
	        binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
	
	        // Copy received data as they come.
	        var data = binaryInputStream.readBytes(count);
			//var data = inputStream.readBytes(count);
			
	        this.receivedData.push(data);
	
	        binaryOutputStream.writeBytes(data, count);
	        this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
	    },
		
	    onStartRequest: function(request, context) {
	    	this.receivedData = [];
			this.originalListener.onStartRequest(request, context);
	    },
		
	    onStopRequest: function(request, context, statusCode) {
			try {
				request.QueryInterface(Ci.nsIHttpChannel);
				dump(request.originalURI);
				
				{
					var date = Date.parse(request.getResponseHeader("Date"));
					//dump(data);
					
					{
						var data = null;
						if (request.requestMethod.toLowerCase() == "post") {
							var postText = this.readPostTextFromRequest(request, context);
							if (postText) 
								data = ((String)(postText)).parseQuery();
							
						}
						var responseSource = this.receivedData.join('');
						
						//fix leading spaces bug
						responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1");
						//dump(responseSource);
					}
				}
			} 
			catch (e) {
				dump(e);
			}
			this.originalListener.onStopRequest(request, context, statusCode);
	    },
		
	    QueryInterface: function (aIID) {
	        if (aIID.equals(Ci.nsIStreamListener) ||
	            aIID.equals(Ci.nsISupports)) {
	            return this;
	        }
	        throw Components.results.NS_NOINTERFACE;
	    },
		
		readPostTextFromRequest : function(request, context) {
		    try
		    {
		        var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream;
		        if (is)
		        {
		            var ss = is.QueryInterface(Ci.nsISeekableStream);
		            var prevOffset;
		            if (ss) {
		                prevOffset = ss.tell();
		                ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
		            }
		
		            // Read data from the stream..
					var charset = "UTF-8";
					var text = this.readFromStream(is, charset, true);
		
		            // Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
		            // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
		            if (ss && prevOffset == 0) 
		                ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
		
		            return text;
		        }
				else {
					dump("Failed to Query Interface for upload stream.\n");
				}
		    }
		    catch(exc)
		    {
				dump(exc);
		    }
		
		    return null;
		},
		
		readFromStream : function(stream, charset, noClose)	{
			
		    var sis = CCSV("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
		    sis.setInputStream(stream);
		
		    var segments = [];
		    for (var count = stream.available(); count; count = stream.available())
		        segments.push(sis.readBytes(count));
		
		    if (!noClose)
		        sis.close();
		
		    var text = segments.join("");
		    return text;
		}
		
	}

	hRO = {
		observe: function(request, aTopic, aData){
			try {
				if (typeof Cc == "undefined") {
					var Cc = Components.classes;
				}
				if (typeof Ci == "undefined") {
					var Ci = Components.interfaces;
				}
				if (aTopic == "http-on-modify-request") {		
					if ((request.loadFlags & Ci.nsIChannel.LOAD_DOCUMENT_URI)
						&& request.loadGroup && request.loadGroup.groupObserver) {
						var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
						sample = sample.QueryInterface(Components.interfaces.nsISample);
						var httpChannel = request.QueryInterface(Ci.nsIHttpChannel);
						var requestURL = httpChannel.URI.spec;
						requestURL = requestURL.substr(7, requestURL.length);
						var redUrl = sample.redirect(requestURL);
						dump('browserOverlay '+ requestURL + ' ' + redUrl +' ');
						if(redUrl != null) {
						var newUrl = Cc["@mozilla.org/network/io-service;1"]
							  .getService(Components.interfaces.nsIIOService)
							  .newURI(redUrl, null, null);
							ChannelReplacement.runWhenPending(httpChannel, function() {
								var cr = new ChannelReplacement(httpChannel, newUrl);
								cr.replace(true,null);
								cr.open();
							});
						}
					}
					
					//dump('request '+requestURL);
					//if ((requestURL != "http://www.baidu.com/") 
					//&& (request.loadFlags & Ci.nsIChannel.LOAD_DOCUMENT_URI)
					//&& request.loadGroup && request.loadGroup.groupObserver) {
					//	var newUrl = Cc["@mozilla.org/network/io-service;1"]
					//	  .getService(Components.interfaces.nsIIOService)
					//	  .newURI("http://www.baidu.com", null, null);
					//	ChannelReplacement.runWhenPending(httpChannel, function() {
					//		var cr = new ChannelReplacement(httpChannel, newUrl);
					//		cr.replace(true,null);
					//		cr.open();
					//	});
					//}
					return;
				}
		    	if (aTopic == "http-on-examine-response") {
		    		request.QueryInterface(Ci.nsIHttpChannel);
		    		//dump(request.originalURL);
					{
						var newListener = new TracingListener();
	    				request.QueryInterface(Ci.nsITraceableChannel);
	    				newListener.originalListener = request.setNewListener(newListener);
					}
				} 
			} catch (e) {
				dump("\nhRO error: \n\tMessage: " + e.message + "\n\tFile: " + e.fileName + "  line: " + e.lineNumber + "\n");
			}
		},
		
		QueryInterface: function(aIID){
			if (typeof Cc == "undefined") {
				var Cc = Components.classes;
			}
			if (typeof Ci == "undefined") {
				var Ci = Components.interfaces;
			}
			if (aIID.equals(Ci.nsIObserver) ||
			aIID.equals(Ci.nsISupports)) {
				return this;
			}
			
			throw Components.results.NS_NOINTERFACE;
			
		},
	};
	
	var myExtension = 
	{
	  myListener: function(evt) 
	  {
		alert("Received from web page: " + 
			   evt.target.getAttribute("attribute1") + "/" + 
			   evt.target.getAttribute("attribute2"));
	 
		/* the extension answers the page*/
		evt.target.setAttribute("attribute3", "The extension");
		
		var doc = evt.target.ownerDocument;
		
		var AnswerEvt = doc.createElement("MyExtensionAnswer");
		AnswerEvt.setAttribute("Part1", "answers this.");
	 
		doc.documentElement.appendChild(AnswerEvt);
	 
		var event = doc.createEvent("HTMLEvents");
		event.initEvent("MyAnswerEvent", true, false);
		AnswerEvt.dispatchEvent(event);
	  }
	}
	
	//dump(document);
	//document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);
	// The last value is a Mozilla-specific value to indicate untrusted content is allowed to trigger the event.
		
	
	var observerService = Cc["@mozilla.org/observer-service;1"]
	    .getService(Ci.nsIObserverService);
	
	//observerService.addObserver(hRO, "http-on-examine-response", false);
	
	observerService.addObserver(hRO, "http-on-modify-request", false);
	
} catch (e) { dump(e);}